package com.example.airole.speech.service.impl;

import com.example.airole.speech.entity.SpeechRecognitionRequest;
import com.example.airole.speech.entity.SpeechRecognitionResponse;
import com.example.airole.speech.service.SpeechRecognitionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Vosk语音识别服务实现
 * 使用Vosk离线语音识别引擎
 */
@Slf4j
@Service("voskSpeechRecognitionService")
public class VoskSpeechRecognitionService implements SpeechRecognitionService {
    
    @Value("${airole.speech.recognition.vosk.model-path:D:/QiNiuYun/models/vosk-model-cn-0.22}")
    private String modelPath;
    
    @Value("${airole.speech.recognition.vosk.enabled:true}")
    private boolean enabled;
    
    private final ExecutorService executorService = Executors.newFixedThreadPool(5);
    private final ConcurrentHashMap<String, SpeechRecognitionResponse> asyncResults = new ConcurrentHashMap<>();
    
    @Override
    public SpeechRecognitionResponse recognize(SpeechRecognitionRequest request) {
        if (!enabled) {
            return SpeechRecognitionResponse.builder()
                    .success(false)
                    .errorMessage("Vosk语音识别服务未启用")
                    .build();
        }
        
        try {
            MultipartFile audioFile = request.getAudioFile();
            if (audioFile == null || audioFile.isEmpty()) {
                return SpeechRecognitionResponse.builder()
                        .success(false)
                        .errorMessage("音频文件不能为空")
                        .build();
            }
            
            long startTime = System.currentTimeMillis();
            
            // 保存临时文件
            String tempFilePath = saveTempFile(audioFile);
            
            try {
                // 调用Vosk进行语音识别
                String recognizedText = recognizeWithVosk(tempFilePath);
                
                long processingTime = System.currentTimeMillis() - startTime;
                
                return SpeechRecognitionResponse.builder()
                        .success(true)
                        .text(recognizedText)
                        .language(request.getLanguage())
                        .confidence(0.95) // Vosk通常有较高的置信度
                        .processingTime(processingTime)
                        .build();
                        
            } finally {
                // 清理临时文件
                deleteTempFile(tempFilePath);
            }
            
        } catch (Exception e) {
            log.error("Vosk语音识别异常", e);
            return SpeechRecognitionResponse.builder()
                    .success(false)
                    .errorMessage("语音识别失败: " + e.getMessage())
                    .build();
        }
    }
    
    @Override
    public String recognizeAsync(SpeechRecognitionRequest request) {
        String taskId = "task_" + System.currentTimeMillis() + "_" + Thread.currentThread().getId();
        
        executorService.submit(() -> {
            try {
                SpeechRecognitionResponse response = recognize(request);
                asyncResults.put(taskId, response);
            } catch (Exception e) {
                log.error("异步语音识别异常", e);
                asyncResults.put(taskId, SpeechRecognitionResponse.builder()
                        .success(false)
                        .errorMessage("异步语音识别失败: " + e.getMessage())
                        .build());
            }
        });
        
        return taskId;
    }
    
    @Override
    public SpeechRecognitionResponse getAsyncResult(String taskId) {
        return asyncResults.get(taskId);
    }
    
    @Override
    public boolean isServiceAvailable() {
        if (!enabled) {
            return false;
        }
        
        // 检查模型文件是否存在
        Path modelDir = Paths.get(modelPath);
        return Files.exists(modelDir) && Files.isDirectory(modelDir);
    }
    
    @Override
    public String[] getSupportedLanguages() {
        return new String[]{"zh-CN", "en-US"};
    }
    
    /**
     * 使用Vosk进行语音识别
     */
    private String recognizeWithVosk(String audioFilePath) throws IOException, InterruptedException {
        // 构建Vosk命令
        ProcessBuilder pb = new ProcessBuilder(
            "python3", "-m", "vosk", 
            "--model", modelPath,
            "--audio", audioFilePath,
            "--output", "json"
        );
        
        pb.redirectErrorStream(true);
        Process process = pb.start();
        
        // 读取输出
        StringBuilder output = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line);
            }
        }
        
        int exitCode = process.waitFor();
        if (exitCode != 0) {
            throw new IOException("Vosk识别失败，退出码: " + exitCode);
        }
        
        // 解析JSON输出，提取文本
        String jsonOutput = output.toString();
        return parseVoskOutput(jsonOutput);
    }
    
    /**
     * 解析Vosk输出JSON
     */
    private String parseVoskOutput(String jsonOutput) {
        try {
            // 简单的JSON解析，提取text字段
            if (jsonOutput.contains("\"text\"")) {
                int start = jsonOutput.indexOf("\"text\":\"") + 8;
                int end = jsonOutput.indexOf("\"", start);
                if (start > 7 && end > start) {
                    return jsonOutput.substring(start, end);
                }
            }
            return "";
        } catch (Exception e) {
            log.error("解析Vosk输出失败", e);
            return "";
        }
    }
    
    /**
     * 保存临时文件
     */
    private String saveTempFile(MultipartFile audioFile) throws IOException {
        String tempDir = System.getProperty("java.io.tmpdir");
        String fileName = "vosk_" + System.currentTimeMillis() + "_" + audioFile.getOriginalFilename();
        Path tempPath = Paths.get(tempDir, fileName);
        
        Files.copy(audioFile.getInputStream(), tempPath);
        return tempPath.toString();
    }
    
    /**
     * 删除临时文件
     */
    private void deleteTempFile(String filePath) {
        try {
            Files.deleteIfExists(Paths.get(filePath));
        } catch (IOException e) {
            log.warn("删除临时文件失败: {}", filePath, e);
        }
    }
}